package cs2340.todolist.model.account_management;

import java.util.regex.Pattern;

import android.content.Context;
import cs2340.todolist.model.User;
import cs2340.todolist.model.sqlite_database.UserAccountDataSource;

public class AccountManager {
	public static final int MIN_PASSWORD_LENGTH = 3;
	public static final int MAX_PASSWORD_LENGTH = 14;
	public static final int MIN_USERNAME_LENGTH = 3;
	public static final int MAX_USERNAME_LENGTH = 14;
	public static final String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
	//current user using the program
	private User 	currentUser;
	private Context context;
	private UserAccountDataSource dataSource;
	
	/**
	 * constructor
	 * @param context the context that will use the AccountManager
	 */
	public AccountManager(Context context) {
		this.setCurrentUser(null);
		this.setContext(context);
		dataSource = new UserAccountDataSource(context);
	}
	
	/**
	 * checks the a string against the user's password
	 * @param pw - the string to check
	 * @return - true if the string matched the user's password, false otherwise
	 */
	public AccountManagementMessage tryToLogin(String username, String password) {				
		AccountManagementMessage returnMessage = new AccountManagementMessage();
		//opens the database
		dataSource.open();
		//gets all users with the username given in the text field.
		// it should only return one of the users because usernames are unique
		currentUser = dataSource.getUserbyUsername(username);
		dataSource.close();
		if(currentUser == null) {
			returnMessage.setMessage(AccountManagementMessage.USER_NOT_FOUND_MESSAGE);
		}
		else if(comparePassword(currentUser.getPassword(),password)) {
			returnMessage.setMessage(AccountManagementMessage.LOGIN_SUCCESSFUL_MESSAGE);
		}
		else {
			returnMessage.setMessage(AccountManagementMessage.USERNAME_PASSWORD_NOT_MATCH_MESSAGE);
		}
		
		return returnMessage;
	}
	

	
	/**
	 * tries to create a user account
	 * @param context - what activity is trying to create the account
	 * @param name - the name of the user
	 * @param email - the user's email 
	 * @param username - desired username
	 * @param password - desired password
	 * @return -1 if the account was not created, the user ID if it was created
	 */
	private long createUserAccount(String name, String email, String username, String password) {
		//UserAccountDataSource dataSource = new UserAccountDataSource(context);
		dataSource.open();
		long insertId = dataSource.insertUser(name, email, username, password);
		dataSource.close();
		return insertId;
	}
	
	/**
	 * checks a password's length
	 * @param password - the password to check
	 * @return true if it fits the required length, false if otherwise
	 */
	public static boolean checkPasswordLength(String password) {
		if(password.length() < MIN_PASSWORD_LENGTH || password.length() > MAX_PASSWORD_LENGTH)
			return false;
		return true;
	}
	
	/**
	 * checks username length
	 * @param username - the username to be checked
	 * @return whether or not it passes
	 */
	public static boolean checkUsernameLength(String username) {
		if(username.length() < MIN_PASSWORD_LENGTH || username.length() > MAX_PASSWORD_LENGTH)
			return false;
		return true;
	}
	
	/**
	 * checks the email to make sure its valid
	 * @param email - the email
	 * @return - whether or not it's valid
	 */
	public static boolean checkEmailPattern(String email) {
		return Pattern.compile(EMAIL_PATTERN).matcher(email).matches();
	}
	
	/**
	 * compares two strings
	 * @param password1 - one version of the password
	 * @param password2 - another version of the password
	 * @return - true if the two passwords match, false otherwise
	 */
	public static boolean comparePassword(String password1, String password2) {
		return password1.equals(password2);
	}
	
	
	public User getCurrentUser() {
		return currentUser;
	}

	public void setCurrentUser(User currentUser) {
		this.currentUser = currentUser;
	}
	
	/**
	 * changes the context
	 * @param newContext the new context to change to
	 */
	public void changeContext(Context newContext){
		setContext(newContext);
		if (dataSource != null){
			dataSource.changeContext(newContext);
		}
	}

	/**
	 * tries to create a new account
	 * 	the following are the account information
	 * @param name
	 * @param email
	 * @param username
	 * @param password
	 * @param retypedPassword
	 * @return whether or not it created the account
	 */
	public AccountManagementMessage tryToCreateAccount(String name, String email, String username, String password, String retypedPassword) {
		AccountManagementMessage returnMessage = new AccountManagementMessage();
		//checks to see if the two passwords entered match
		if(!comparePassword(password, retypedPassword))
			returnMessage.setMessage(AccountManagementMessage.PASSWORD_NOT_MATCH_MESSAGE);
		
		//checks to see if the username is a valid length
		else if(!checkUsernameLength(username))
			returnMessage.setMessage(AccountManagementMessage.INVALID_USERNAME_MESSAGE);
		
		//checks to see if the password is a valid length
		else if(!checkPasswordLength(password))
			returnMessage.setMessage(AccountManagementMessage.INVALID_PASSWORD_MESSAGE);
		//if it passes all the previous tests, try to create an account with the information provided.
		else if(!checkEmailPattern(email)) {
			returnMessage.setMessage(AccountManagementMessage.INVALID_EMAIL);
		}
		else {
			//tries to create an account, will return the ID if it is successful and -1 if it's not
			// the only way it wont be successful is if the username is already taken
			long newUserId = createUserAccount(name, email, username, password);
			
			//if the return from account creation was -1 (which means the username was already taken)
			// then tell the user that his username is already taken
			if(newUserId == -1)
				returnMessage.setMessage(AccountManagementMessage.USERNAME_IN_USE_MESSAGE);
			//if it was available and the account was successfully added to the account, then display the account created dialog
			else {
				returnMessage.setMessage(AccountManagementMessage.ACCOUNT_CREATED_MESSAGE);
			}
		}
		
		return returnMessage;
	}
	
	public Context getContext() {
		return context;
	}

	public void setContext(Context context) {
		this.context = context;
	}

	public class AccountManagementMessage {
		public static final String ACCOUNT_CREATED_MESSAGE		= "Account Successfully Created!\nReturning to login screen!";
		public static final String LOGIN_SUCCESSFUL_MESSAGE		= "Login was successful!";
		public static final String PASSWORD_NOT_MATCH_MESSAGE 	= "Passwords do not match!";
    	public static final String INVALID_USERNAME_MESSAGE 	= "Invalid Username.\nUsernames must be greater than " + MIN_USERNAME_LENGTH + " and less than " + MAX_USERNAME_LENGTH + " characters long!";
    	public static final String INVALID_PASSWORD_MESSAGE		= "Invalid Password.\nPasswords must be greater than " + MIN_PASSWORD_LENGTH + " and less than " + MAX_PASSWORD_LENGTH + " characters long!";
    	public static final String INVALID_EMAIL				= "Invalid Email. \nThe email you provided does not look like an email!";
    	public static final String USERNAME_IN_USE_MESSAGE		= "Username already in use. Sorry!";
    	public static final String USERNAME_PASSWORD_NOT_MATCH_MESSAGE = "Username and/or password did not match.";
    	public static final String USER_NOT_FOUND_MESSAGE		= "Username not found. Please retype your username";
    	
    	private String message;
    	
    	private AccountManagementMessage() {
    		message = "";
    	}
    	
    	private AccountManagementMessage(String message) {
    		this.message = message;
    	}
    	
    	private void setMessage(String message) {
    		this.message = message;
    	}
    	
    	public String getMessage() {
    		return message;
    	}
    	
	}
	
	
}
